//===============================================================================
// Microsoft patterns & practices
// Mobile Client Software Factory - July 2006
//===============================================================================
// Copyright  Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===============================================================================
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious.  No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
//===============================================================================

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.Practices.Mobile.DisconnectedAgent.Tests.Mocks;
using Microsoft.Practices.Mobile.EndpointCatalog;

namespace Microsoft.Practices.Mobile.DisconnectedAgent.Tests
{
	[TestClass]
	public class WebServiceRequestDispatcherFixture
	{
		[TestMethod]
		public void RequestDispatcherIsCreatedAssociatedToAProxyFactory()
		{
			IProxyFactory mockFactory = new SimpleOnlineProxyFactory();
			WebServiceRequestDispatcher dispatcher = new WebServiceRequestDispatcher(mockFactory);

			Assert.AreSame(mockFactory, dispatcher.OnlineProxyFactory);
		}

		[TestMethod]
		public void DispatchingRequestWithNoParamsCausesCallback()
		{
			Request r = new Request();
			r.Endpoint = "Endpoint";
			r.OnlineProxyType = typeof(MockService);
			r.MethodName = "DoWithNoParams";

			r.Behavior.ReturnCallback = new CommandCallback(typeof(OfflineMockServiceCallbacks), "OnDoWithNoParamsReturn");

            WebServiceRequestDispatcher dispatcher = new WebServiceRequestDispatcher(CreateMockCatalog(), new MockCredentialService(null));
			DispatchResult result = dispatcher.Dispatch(r, "Network");
			Assert.AreEqual(DispatchResultStatus.Succeeded, result.DispatchResultStatus);

			Assert.IsTrue(MockService.Invoked, "MockService not invoked");

			Assert.IsTrue(OfflineMockServiceCallbacks.ReturnInvoked, "Callback not invoked");
			Assert.IsNotNull(OfflineMockServiceCallbacks.LastRequest);
			Assert.AreSame(r, OfflineMockServiceCallbacks.LastRequest);
		}

		[TestMethod]
		public void DispatchingRequestWithParamsCausesCallback()
		{
			Request r = new Request();
			r.Endpoint = "Endpoint";
			r.OnlineProxyType = typeof(MockService);
			r.MethodName = "DoWithParamsAndReturn";
			r.CallParameters = CallParameters.ToArray(1, new MockServiceDataContract("Peter", 25));

			r.Behavior.ReturnCallback = new CommandCallback(typeof(OfflineMockServiceCallbacks), "OnDoWithParamsAndReturnReturn");

            WebServiceRequestDispatcher dispatcher = new WebServiceRequestDispatcher(CreateMockCatalog(), new MockCredentialService(null));
			DispatchResultStatus result = dispatcher.Dispatch(r, "Network").DispatchResultStatus;
			Assert.AreEqual(DispatchResultStatus.Succeeded, result);

			Assert.IsTrue(MockService.Invoked, "MockService not invoked");

			Assert.IsTrue(OfflineMockServiceCallbacks.ReturnInvoked, "Callback not invoked");
			Assert.IsNotNull(OfflineMockServiceCallbacks.LastRequest);
			Assert.AreSame(r, OfflineMockServiceCallbacks.LastRequest);
		}

		[TestMethod]
		public void DispatchWithNullCallbackDoesntFail()
		{
			Request r = new Request();
			r.Endpoint = "Endpoint";
			r.OnlineProxyType = typeof(MockService);
			r.MethodName = "DoWithNoParams";

            WebServiceRequestDispatcher dispatcher = new WebServiceRequestDispatcher(CreateMockCatalog(), new MockCredentialService(null));
			DispatchResultStatus result = dispatcher.Dispatch(r, "Network").DispatchResultStatus;

			Assert.AreEqual(DispatchResultStatus.Succeeded, result);
			Assert.IsTrue(MockService.Invoked);
		}

		[TestMethod]
		public void DispatchWithReturnButNullCausesCallback()
		{
			Request r = new Request();
			r.Endpoint = "Endpoint";
			r.OnlineProxyType = typeof(MockService);
			r.MethodName = "DoWithNoParamsAndStringReturn";

			r.Behavior.ReturnCallback = new CommandCallback(typeof(OfflineMockServiceCallbacks), "OnDoWithNoParamsAndStringReturnReturn");

            WebServiceRequestDispatcher dispatcher = new WebServiceRequestDispatcher(CreateMockCatalog(), new MockCredentialService(null));
			DispatchResultStatus result = dispatcher.Dispatch(r, "Network").DispatchResultStatus;
			Assert.AreEqual(DispatchResultStatus.Succeeded, result);

			Assert.IsTrue(MockService.Invoked, "MockService not invoked");

			Assert.IsTrue(OfflineMockServiceCallbacks.ReturnInvoked, "Callback not invoked");
			Assert.IsNotNull(OfflineMockServiceCallbacks.LastRequest);
			Assert.AreSame(r, OfflineMockServiceCallbacks.LastRequest);
		}

		[TestMethod]
		public void DispatchingRequestWithOutParamsCausesCallback()
		{
			Request r = new Request();
			r.Endpoint = "Endpoint";
			r.OnlineProxyType = typeof(MockService);
			r.MethodName = "DoWithOutParamsAndReturn";
			int outNumber = 0;
			MockServiceDataContract outObject = new MockServiceDataContract("", 0);
			r.CallParameters = CallParameters.ToArray(1, outNumber, new MockServiceDataContract("Peter", 25), outObject);

			r.Behavior.ReturnCallback = new CommandCallback(typeof(OfflineMockServiceCallbacks), "OnDoWithOutParamsAndReturnReturn");

            WebServiceRequestDispatcher dispatcher = new WebServiceRequestDispatcher(CreateMockCatalog(), new MockCredentialService(null));
			DispatchResultStatus result = dispatcher.Dispatch(r, "Network").DispatchResultStatus;
			Assert.AreEqual(DispatchResultStatus.Succeeded, result);
			Assert.AreEqual(1, (int)OfflineMockServiceCallbacks.LastParams[0]); //in
			Assert.AreEqual(1, (int)OfflineMockServiceCallbacks.LastParams[1]); //out
			Assert.AreEqual("Peter", ((MockServiceDataContract)OfflineMockServiceCallbacks.LastParams[2]).Name); //in
			Assert.AreEqual(25, ((MockServiceDataContract)OfflineMockServiceCallbacks.LastParams[2]).Age); //in
			Assert.AreEqual("Peter", ((MockServiceDataContract)OfflineMockServiceCallbacks.LastParams[3]).Name); //out
			Assert.AreEqual(25, ((MockServiceDataContract)OfflineMockServiceCallbacks.LastParams[3]).Age); //out

			Assert.IsTrue(MockService.Invoked, "MockService not invoked");
			Assert.IsTrue(OfflineMockServiceCallbacks.ReturnInvoked, "Callback not invoked");
			Assert.IsNotNull(OfflineMockServiceCallbacks.LastRequest);
			Assert.AreSame(r, OfflineMockServiceCallbacks.LastRequest);
		}

		[TestMethod]
		public void OnExceptionDuringDispatchOnExceptionCallbackIsCalledReceivingTheRequest()
		{
			Request r = new Request();
			r.Endpoint = "Endpoint";
			r.OnlineProxyType = typeof(MockService);
			r.MethodName = "DoThrowingAnException";
			r.Behavior.ExceptionCallback = new CommandCallback(typeof(OfflineMockServiceCallbacks), "OnMockServiceException");

            WebServiceRequestDispatcher dispatcher = new WebServiceRequestDispatcher(CreateMockCatalog(), new MockCredentialService(null));
			DispatchResultStatus result = dispatcher.Dispatch(r, "Network").DispatchResultStatus;

			Assert.IsTrue(OfflineMockServiceCallbacks.ExceptionInvoked, "Exception Callback not invoked");
			Assert.AreEqual(OfflineMockServiceCallbacks.LastException.GetType(), typeof(MockException));
			Assert.AreEqual(r, OfflineMockServiceCallbacks.LastRequest);
		}

		[TestMethod]
		public void OnExceptionDuringReturnCallbackOnExceptionCallbackIsCalledWithReturnCallbackException()
		{
			Request r = new Request();
			r.Endpoint = "Endpoint";
			r.OnlineProxyType = typeof(MockService);
			r.MethodName = "DoWithNoParams";

			r.Behavior.ReturnCallback = new CommandCallback(typeof(OfflineMockServiceCallbacks), "OnDoWithNoParamSReturnThrowingException");
			r.Behavior.ExceptionCallback = new CommandCallback(typeof(OfflineMockServiceCallbacks), "OnMockServiceException");

            WebServiceRequestDispatcher dispatcher = new WebServiceRequestDispatcher(CreateMockCatalog(), new MockCredentialService(null));
			DispatchResultStatus result = dispatcher.Dispatch(r, "Network").DispatchResultStatus;
			Assert.IsTrue(OfflineMockServiceCallbacks.ReturnInvoked, "Return callbck not invoked");
			Assert.IsTrue(OfflineMockServiceCallbacks.ExceptionInvoked, "Exception Callback not invoked");
			Assert.AreEqual(OfflineMockServiceCallbacks.LastException.GetType(), typeof(ReturnCallbackException));
			Assert.AreEqual(OfflineMockServiceCallbacks.LastException.InnerException.GetType(), typeof(MockException));
			Assert.AreEqual(r, OfflineMockServiceCallbacks.LastRequest);
		}

		[TestMethod]
		public void OnExceptionReturningRetryDispatcherRetriesUpToMaxRetriesThenReturnsFailed()
		{
			Request r = new Request();
			r.Endpoint = "Endpoint";
			r.OnlineProxyType = typeof(MockService);
			r.MethodName = "DoThrowingAnException";
			r.Behavior.ExceptionCallback = new CommandCallback(typeof(OfflineMockServiceCallbacks), "OnMockServiceException");

            WebServiceRequestDispatcher dispatcher = new WebServiceRequestDispatcher(CreateMockCatalog(), new MockCredentialService(null));
			MockService.InvokedTimes = 0;
			r.Behavior.MaxRetries = 5;
			DispatchResultStatus result = dispatcher.Dispatch(r, "Network").DispatchResultStatus;

			Assert.AreEqual(DispatchResultStatus.Failed, result);
			Assert.AreEqual(6, MockService.InvokedTimes);
			Assert.IsTrue(OfflineMockServiceCallbacks.ExceptionInvoked, "Exception Callback not invoked");
			Assert.AreEqual(OfflineMockServiceCallbacks.LastException.GetType(), typeof(MockException));
			Assert.AreEqual(r, OfflineMockServiceCallbacks.LastRequest);
		}

		[TestMethod]
		public void OnExceptionReturningDismissDispatcherReturnsFailed()
		{
			Request r = new Request();
			r.Endpoint = "Endpoint";
			r.OnlineProxyType = typeof(MockService);
			r.MethodName = "DoThrowingAnException";
			r.Behavior.ExceptionCallback = new CommandCallback(typeof(OfflineMockServiceCallbacks), "OnMockServiceExceptionRetriesTwice");

            WebServiceRequestDispatcher dispatcher = new WebServiceRequestDispatcher(CreateMockCatalog(), new MockCredentialService(null));
			MockService.InvokedTimes = 0;
			r.Behavior.MaxRetries = 5;
			DispatchResultStatus result = dispatcher.Dispatch(r, "Network").DispatchResultStatus;

			Assert.AreEqual(DispatchResultStatus.Failed, result);
			Assert.AreEqual(3, MockService.InvokedTimes); //Two retries then Dismiss
			Assert.IsTrue(OfflineMockServiceCallbacks.ExceptionInvoked, "Exception Callback not invoked");
			Assert.AreEqual(OfflineMockServiceCallbacks.LastException.GetType(), typeof(MockException));
			Assert.AreEqual(r, OfflineMockServiceCallbacks.LastRequest);
		}

		[TestMethod]
		public void OnMissingExceptionCallbackDispatcherReturnsFailed()
		{
			Request r = new Request();
			r.Endpoint = "Endpoint";
			r.OnlineProxyType = typeof(MockService);
			r.MethodName = "DoThrowingAnException";
			r.Behavior.ExceptionCallback = new CommandCallback(typeof(OfflineMockServiceCallbacks), "OnMockServiceMissingOnException");

            WebServiceRequestDispatcher dispatcher = new WebServiceRequestDispatcher(CreateMockCatalog(), new MockCredentialService(null));
			MockService.InvokedTimes = 0;
			r.Behavior.MaxRetries = 5;
			DispatchResultStatus result = dispatcher.Dispatch(r, "Network").DispatchResultStatus;

			Assert.AreEqual(DispatchResultStatus.Failed, result);
		}

		[TestMethod]
		public void OnExceptionThrowingExceptionDispatcherReturnsFailed()
		{
			Request r = new Request();
			r.Endpoint = "Endpoint";
			r.OnlineProxyType = typeof(MockService);
			r.MethodName = "DoThrowingAnException";
			r.Behavior.ExceptionCallback = new CommandCallback(typeof(OfflineMockServiceCallbacks), "OnMockServiceExceptionThrowsException");

            WebServiceRequestDispatcher dispatcher = new WebServiceRequestDispatcher(CreateMockCatalog(), new MockCredentialService(null));
			MockService.InvokedTimes = 0;
			r.Behavior.MaxRetries = 5;
			DispatchResultStatus result = dispatcher.Dispatch(r, "Network").DispatchResultStatus;

			Assert.AreEqual(DispatchResultStatus.Failed, result);
		}

		private IEndpointCatalog CreateMockCatalog()
		{
			Microsoft.Practices.Mobile.EndpointCatalog.EndpointCatalog catalog = new Microsoft.Practices.Mobile.EndpointCatalog.EndpointCatalog();
			Endpoint endpoint = new Endpoint("Endpoint");
			endpoint.Default = new EndpointConfig("http://localhost/");
			catalog.SetEndpoint(endpoint);
			return catalog;
		}
	}
}
